#include <sstream>
#include <stdexcept>
#include <ruby.h>

using namespace std;




void BacktraceIfError(int error) {
    if(error == 0)
        return;

    VALUE lasterr = rb_gv_get("$!");

    // class
    VALUE klass = rb_class_path(CLASS_OF(lasterr));
	clog << "class: " << RSTRING(klass)->ptr << endl; 

    // message
    VALUE message = rb_obj_as_string(lasterr);
	clog << "message: " << RSTRING(message)->ptr << endl;

    // backtrace
    if(!NIL_P(ruby_errinfo)) {
        std::ostringstream o;
        VALUE ary = rb_funcall(
            ruby_errinfo, rb_intern("backtrace"), 0);
        int c;
        for (c=0; c<RARRAY(ary)->len; c++) {
            o << "\tfrom " << 
                RSTRING(RARRAY(ary)->ptr[c])->ptr << 
                "\n";
        }
		clog << "backtrace: " << endl << o.str() << endl;
    }
}

void ThrowOnError(int error) {
   BacktraceIfError(error);
   throw runtime_error("ruby_error");
}

#define RUBY_TRY \
    extern VALUE ruby_errinfo; \
    ruby_errinfo = Qnil; \
    try

#define RUBY_CATCH \
    catch(const std::exception &e) { \
        std::ostringstream o; \
        o << "c++error: " << e.what(); \
        ruby_errinfo = rb_exc_new2( \
            rb_eRuntimeError, o.str().c_str()); \
    } catch(...) { \
        ruby_errinfo = rb_exc_new2( \
            rb_eRuntimeError, "c++error: Unknown error"); \
    } \
    if(!NIL_P(ruby_errinfo)) { \
        rb_exc_raise(ruby_errinfo); \
    }
